package com.zhouyu.mysql.core;

import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.util.ByteUtil;
import com.zhouyu.mysql.dict.DictColumn;
import com.zhouyu.mysql.dict.DictTable;
import com.zhouyu.mysql.dict.SystemDict;
import com.zhouyu.mysql.page.IndexPage;

import java.nio.ByteBuffer;
import java.util.HashMap;

import static com.zhouyu.mysql.core.ByteBufferUtil.*;

/**
 * 大都督周瑜（我的微信: dadudu6789）
 */
public class RecUtil {

    public final static int REC_HEADER_SIZE = 5; /* 记录头包括2个字节heap_no、1个字节record_type、2个字节next_record */
    public final static int REC_NEXT = 2; /* 用2个字节来存前一条记录的觉得地址 */

    /**
     * 获取某条记录的下一条记录，返回值为下一条记录的中间位置
     * @param indexPage 某页
     * @param rec 某条记录的中间位置
     * @return 下一条记录的中间位置
     */
    public static int rec_get_next_offs(IndexPage indexPage, int rec) {
        return mach_read_from_2(indexPage.getPageByteBuffer(), rec - REC_NEXT);
    }

    /**
     * 用DTuple和rec执行的记录进行比较，要么比较id字段，要么比较id字段的后一个字段
     * @param indexPage 某页
     * @param tuple 某数据组
     * @param rec 指针，执行某条记录的中间
     * @return 大小关系，1表示DTuple大于rec
     */
    public static int cmp_dtuple_rec_with_match_low(IndexPage indexPage, DTuple tuple, int rec) {
        DField field = tuple.getFields().get(0);
        if ("id".equals(field.getDictColumn().getName())) {
            int fieldId = (int) field.getData();
            int recId = mach_read_from_4(indexPage.pageByteBuffer, rec);
            return CompareUtil.compare(fieldId, recId);
        } else {
            String fieldName = (String) field.getData();
            // 跳过id的4个字节
            String recName = mach_read_from_size_str(indexPage.pageByteBuffer, rec + 4, field.getDictColumn().getLen());
            return CompareUtil.compare(fieldName, recName);
        }
    }

    /**
     * 计算新数据占用多少个字节
     *
     * @param dTuple 待插入新数据
     * @return 新数据字节数
     */
    public static int rec_get_converted_size(DTuple dTuple) {
        int size = 0;
        for (DField field : dTuple.getFields()) {
            size += field.getDictColumn().getLen();
        }
        return size + REC_HEADER_SIZE;
    }


    /**
     * 把dTuple转成记录ByteBuffer
     *
     * @param indexPage 当前页
     * @param dTuple    新记录数据
     * @return 新记录字节ByteBuffer，position指向了记录起始位，不是中间位
     */
    public static ByteBuffer rec_convert_dtuple_to_rec(IndexPage indexPage, DTuple dTuple) {
        int recSize = RecUtil.rec_get_converted_size(dTuple);
        ByteBuffer rec = ByteBuffer.allocate(recSize);

        // 在之前的page_mem_alloc_heap()已经加过1了，这里拿出来直接用就可以了
        int position = indexPage.pageByteBuffer.position();
        int pageNHeap = indexPage.get_n_heap() - 1;
        indexPage.pageByteBuffer.position(position);
        ByteBufferUtil.mach_write_to_2(rec, 0, pageNHeap);

        // 0表示普通记录
        ByteBufferUtil.mach_write_to_1(rec, 2, 0);

        // next_record后面在设置，先占用4个字节
        ByteBufferUtil.mach_write_to_2(rec, 3, 0);

        // 指向记录中间位置，插入字段数据
        rec.position(REC_HEADER_SIZE);
        for (DField field : dTuple.getFields()) {
            if (field.getDictColumn().isInt()) {
                rec.put(ByteUtil.intToBytes((Integer) field.getData()));
            } else {
                rec.put(((String) field.getData()).getBytes());
            }
        }

        // 指向记录的起始位
        rec.clear();

        return rec;
    }



    /**
     * 读取记录内容
     *
     * @param indexPage 指定页
     * @param rec       记录中间位置
     * @return 记录内容
     */
    public static HashMap<String, Object> getRecContent(IndexPage indexPage, int rec) {

        HashMap<String, Object> content = new HashMap<>();

        DictTable dictTable = SystemDict.getInstance().getSpaceIdTables().get(indexPage.fil_page_get_space_id());
        for (DictColumn dictColumn : dictTable.getDictColumnList()) {
            if (dictColumn.isInt()) {
                byte[] bytes = new byte[4];
                indexPage.getPageByteBuffer().get(rec, bytes);
                rec = rec + 4;
                content.put(dictColumn.getName(), ByteUtil.bytesToInt(bytes));
            } else {
                byte[] bytes = new byte[2];
                indexPage.getPageByteBuffer().get(rec, bytes);
                rec = rec + 2;
                String value = new String(bytes);
                // "00"表示字段内容为null
                if ("00".equals(value)) {
                    content.put(dictColumn.getName(), null);
                } else {
                    content.put(dictColumn.getName(), value);
                }

            }
        }

        return content;
    }
}
